package com.jdd.modules.rabbitMq;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jdd.common.api.vo.Result;
import com.jdd.common.api.vo.ResultVo;
import com.jdd.common.api.vo.WebSocketVo;
import com.jdd.common.constant.CacheConstant;
import com.jdd.common.constant.JddConstant;
import com.jdd.common.constant.MessageTypeConstant;
import com.jdd.common.entity.RabbitMqMessage;
import com.jdd.common.exception.JddException;
import com.jdd.common.util.*;
import com.jdd.config.websocket.WebSocketServer;
import com.jdd.modules.operationLog.service.IParkHandOverLogService;
import com.jdd.modules.order.entity.ParkOrderInfo;
import com.jdd.modules.order.mapper.ParkOrderInfoMapper;
import com.jdd.modules.parkCarAbnormalRecord.service.IParkCarAbnormalRecordService;
import com.jdd.modules.parkWhiteEdit.entity.ParkWhiteEditList;
import com.jdd.modules.parkWhiteEdit.service.IParkWhiteEditListService;
import com.jdd.modules.parkcar.entity.ParkCarMonthly;
import com.jdd.modules.parkcar.entity.ParkCarOutAbnormalLog;
import com.jdd.modules.parkcar.entity.ParkSpace;
import com.jdd.modules.parkcar.entity.ParkWhiteList;
import com.jdd.modules.parkcar.mapper.ParkWhiteListMapper;
import com.jdd.modules.parkcar.service.IParkCarMonthlyService;
import com.jdd.modules.parkcar.service.IParkCarOutAbnormalLogService;
import com.jdd.modules.parkcar.service.IParkSpaceService;
import com.jdd.modules.parking.entity.OpenGateVo;
import com.jdd.modules.parking.entity.ParkArmInfo;
import com.jdd.modules.parking.entity.ParkCarEnterLog;
import com.jdd.modules.parking.entity.ParkCarOutLog;
import com.jdd.modules.parking.mapper.ParkArmInfoMapper;
import com.jdd.modules.parking.mapper.ParkCarEnterLogMapper;
import com.jdd.modules.parking.mapper.ParkCarOutLogMapper;
import com.jdd.modules.parking.service.IParkArmInfoService;
import com.jdd.modules.parking.service.IParkCarOutEntranceRecordService;
import com.jdd.modules.parking.service.IParkWorkStationService;
import com.jdd.modules.sdk.LedCallInterface;
import com.jdd.modules.sdk.SdkCallInterface;
import com.jdd.modules.sdkidentifyresultpushlog.service.ISdkIdentifyResultPushLogV3Service;
import com.jdd.modules.visitors.entity.VisitorRecord;
import com.jdd.modules.visitors.mapper.VisitorRecordMapper;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

import static com.jdd.common.constant.CacheConstant.CURRENT_EXIT_LICENSE_PLATE_TEN;

/**
 * @version 1.0
 * @Description:
 * @author： jdd尚岳
 * @Date: 2021-05-27 17:01
 */
@Component
@Slf4j

public class ParkCloudOrderListener {

    public String appScrect;

    public String appId;
    @Value("${parkInfo.parkCode}")
    public String parkCode;
    @Value("${park.field.pay}")
    public String fueldPay;
    @Resource
    ParkOrderInfoMapper orderInfoMapper;
    @Resource
    RestTemplateUtils restTemplateUtils;


    @Value("${park.app.url}")
    private String parkAppUrl;
    @Resource
    private SdkCallInterface sdkCallInterface;
    @Resource
    private ParkCarEnterLogMapper parkCarEnterLogMapper;
    @Resource
    private ParkCarOutLogMapper parkCarOutLogMapper;
    @Resource
    private IParkArmInfoService parkArmInfoService;
    @Resource
    private ParkArmInfoMapper parkArmInfoMapper;
    @Resource
    private CacheUtil cacheUtil;
    @Resource
    private WebSocketServer socketServer;
    @Resource
    private VisitorRecordMapper visitorRecordMapper;
    @Resource
    private ParkWhiteListMapper parkWhiteListMapper;
    @Resource
    private IParkSpaceService parkSpaceService;
    @Resource
    private IParkCarOutAbnormalLogService parkCarOutAbnormalLogService;
    @Resource
    private IParkCarMonthlyService parkCarMonthlyService;
    @Resource
    private IParkWhiteEditListService parkWhiteEditListService;
    @Resource
    private ExecutorService executorService;
    @Resource
    private IParkWorkStationService parkWorkStationService;
    @Resource
    private IParkHandOverLogService parkHandOverLogService;
    @Resource
    private ParkOrderInfoMapper parkOrderInfoMapper;
    @Resource
    private LedCallInterface ledCallInterface;
    @Resource
    private ISdkIdentifyResultPushLogV3Service sdkIdentifyResultPushLogV3Service;
    @Resource
    MonthlyUploadHttpUtils monthlyUploadHttpUtils;
    @Resource
    IParkCarOutEntranceRecordService parkCarOutEntranceRecordService;
    @RabbitListener(queues = "${park.station.queue}")
    @RabbitHandler
    public void receiveMessage(@Payload String body, @Headers Map<String, Object> headers, Channel channel) throws IOException {
        log.info("接收到云端消息{}", body);
        Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        RabbitMqMessage rabbitMqMessage = null;

        try {
            rabbitMqMessage = JSON.parseObject(body, RabbitMqMessage.class);
        } catch (Exception e) {
            log.error("消息转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }

        if (null == rabbitMqMessage || StringUtils.isBlank(rabbitMqMessage.getMessageType()) || StringUtils.isBlank(rabbitMqMessage.getMessageBody())) {
            log.info("空消息{}", JSON.toJSONString(rabbitMqMessage));
            //空消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }

        //处理消息
        try {
            process(rabbitMqMessage, deliveryTag, channel);
            //确认消息
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            log.error("处理消息异常：{}", e.getMessage());
            //抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
        }

    }
    @Resource
    private IParkCarAbnormalRecordService parkCarAbnormalRecordService;


    /**
     * @return void
     * @Description 业务不同异常处理(消息确认 、 消息返回队列 、 消息抛弃)
     * @Author wanglei
     * @Date 2021-06-02 17:28
     * @Param [rabbitMqMessage, deliveryTag, channel]
     * @version 1.0
     **/
    private void process(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        //支付结果消息
        if (MessageTypeConstant.MESSAGE_TYPE_ORDER.equals(rabbitMqMessage.getMessageType())) {
            ParkOrderInfo parkOrderInfo = null;
            try {
                parkOrderInfo = JSON.parseObject(rabbitMqMessage.getMessageBody(), ParkOrderInfo.class);
            } catch (Exception e) {
                log.error("消息(支付结果)转换异常", e.getMessage());
                //非法消息，抛弃此条消息
                channel.basicNack(deliveryTag, false, false);
                return;
            }
            if (null != parkOrderInfo && JddConstant.OrderConstant.ORDER_PAY_STATE_SUCCESS.equals(parkOrderInfo.getOrderStatus())) {
                log.info("临时车支付成功,同步订单记录:{}", rabbitMqMessage.getMessageBody());
                ParkCarOutLog parkCarOutLog = new ParkCarOutLog();
                try {
                    //是否异常出场
                    int abnormal = 0;
                    //出口车牌与消息通知车牌一致开闸
                    String plateNo = null;
                    String ossImg = null;
                    String img = null;
                    String armName = null;
                    String serialNo =null;
                    Map<String, String> map = getCarInfo(parkOrderInfo.getSerialNo());
                    if (map.size() > 0) {
                        plateNo = map.get("plateNo");
                        ossImg = map.get("ossImg");
                        img = map.get("img");
                        armName = map.get("armName");
                    }

                    //出口车牌与消息通知车牌一致开闸
                    if (StringUtils.isNotBlank(plateNo) && StringUtils.isNotBlank(parkOrderInfo.getSerialNo())) {
                        if (!"_无_".equals(plateNo)) {
                            if (StringUtils.isNotBlank(parkOrderInfo.getPlateNo())) {
                                log.info("临时车开闸:SerialNo:{}>PlateNo:{}", parkOrderInfo.getSerialNo(), plateNo);
                                //获取入场识别错误车牌号
                                String plateNoFalse = cacheUtil.get("truePlateNo", plateNo);
                                //车辆出场入场记录识别错误 匹配情况走下列方法
                                //判断是否存在重新匹配的车牌
                                if (StringUtils.isNotBlank(plateNoFalse)) {
                                    //组装修改内容
                                    ParkCarEnterLog carEnterLog = new ParkCarEnterLog();
                                    carEnterLog.setIsOut("1");
                                    carEnterLog.setPlateNo(plateNo);
                                    carEnterLog.setEnterType(JddConstant.IntNumber.INT_TWO);
                                    carEnterLog.setRemark("入场时识别为" + plateNoFalse);
                                    //组装修改条件
                                    LambdaQueryWrapper<ParkCarEnterLog> lambdaQueryWrapper = new LambdaQueryWrapper();
                                    lambdaQueryWrapper.eq(ParkCarEnterLog::getBatchNumber, parkOrderInfo.getCarEnterId());
                                    //降入场记录表中匹配的假车牌更新为出场识别照片
                                    parkCarEnterLogMapper.update(carEnterLog, lambdaQueryWrapper);
                                    cacheUtil.delete("truePlateNo", plateNo);
                                    ParkArmInfo parkArmInfo = parkArmInfoMapper.queryParkArmInfoBySerialNo(parkOrderInfo.getSerialNo());
                                    ParkCarOutAbnormalLog abnormalLog = new ParkCarOutAbnormalLog();
                                    BeanUtils.copyProperties(parkOrderInfo, abnormalLog);
                                    abnormalLog.setId(SnowFlakeUtil.getId());
                                    abnormalLog.setArmName(parkArmInfo.getArmName());
                                    abnormalLog.setIpAddr(parkArmInfo.getIpAddr());
                                    abnormalLog.setPayStatus("2");
                                    abnormalLog.setRecordType("5");
                                    abnormalLog.setRemark("扫码支付,入口识别车牌:" + plateNoFalse);
                                    parkCarOutAbnormalLogService.save(abnormalLog);
                                    abnormal = 1;
                                } else {
                                    // 如果不是匹配入场记录出场的车辆
                                    ParkCarOutAbnormalLog parkCarOutAbnormalLog = new ParkCarOutAbnormalLog();
                                    parkCarOutAbnormalLog.setPayStatus("2");
                                    parkCarOutAbnormalLog.setRemark("扫码支付");
                                    LambdaQueryWrapper<ParkCarOutAbnormalLog> queryWrapper = new LambdaQueryWrapper<>();
                                    queryWrapper.eq(ParkCarOutAbnormalLog::getCarEnterId, parkOrderInfo.getCarEnterId());
                                    boolean update = parkCarOutAbnormalLogService.update(parkCarOutAbnormalLog, queryWrapper);
                                    if (update) {
                                        abnormal = 1;
                                    }
                                }
                                //
                                ledCallInterface.FieldFeeAll(parkOrderInfo.getSerialNo(), plateNo);
                                // 车辆出场缓存车辆，处理重复出场
                            	cacheUtil.put(CacheConstant.PARK_CAR_OUT, parkOrderInfo.getSerialNo(), plateNo);
                            	log.info("出口码支付成功缓存当前车道已出场车牌信息->{},车道信息->{}",plateNo,serialNo);
                            }

                        } else {
                            ledCallInterface.FieldFeeAll(parkOrderInfo.getSerialNo(), "无牌车");

                            log.info("无牌车开闸:SerialNo:{}>PlateNo:{}", parkOrderInfo.getSerialNo(), "无牌车");
                        }
                    }
                    //场内码支付
                    parkOrderInfo.setArmName(armName);
                    orderInfoMapper.insert(parkOrderInfo);
                    if (StringUtils.isNotBlank(parkOrderInfo.getPlateNo()) && StringUtils.isBlank(parkOrderInfo.getSerialNo())) {
                        Boolean isBasicAck =true;
                        if (JddConstant.StringNumber.STRING_ONE.equals(fueldPay)){
                            Map<String, String> maps = getCarInfos(parkOrderInfo.getPlateNo());
                            if (CollectionUtil.isNotEmpty(maps)) {
                                isBasicAck =false;
                                plateNo = maps.get("plateNo");
                                ossImg = maps.get("ossImg");
                                img = maps.get("img");
                                armName = maps.get("armName");
                                serialNo = maps.get("serialNo");
                                parkOrderInfo.setSerialNo(serialNo);
                                // 抬杆播报
                                ledCallInterface.FieldFeeAll(parkOrderInfo.getSerialNo(), plateNo);
                                // 清除缓存
                                cacheUtil.delete(CacheConstant.CURRENT_EXIT_LICENSE_PLATE,serialNo);
                                // 车辆出场缓存车辆，处理重复出场
                                cacheUtil.put(CacheConstant.PARK_CAR_OUT, serialNo, plateNo);
                                log.info("场内码支付成功缓存当前车道已出场车牌信息->{},车道信息->{}",plateNo,serialNo);
                            }
                        }
                        if (JddConstant.StringNumber.STRING_TWO.equals(fueldPay)){
                            Map<String, String> maps = getCarInfos(parkOrderInfo.getPlateNo());
                            if (CollectionUtil.isNotEmpty(maps)) {
                                plateNo = maps.get("plateNo");
                                ossImg = maps.get("ossImg");
                                img = maps.get("img");
                                armName = maps.get("armName");
                                serialNo = maps.get("serialNo");
                                String str = cacheUtil.get(CacheConstant.GET_SDK_DOCK_CAR, serialNo);
                                log.info("场内码支付获取地感状态->{},str->{}",JddConstant.StringNumber.STRING_ZERO.equals(str)?"有车停靠":"无车辆停靠",str);
                                if (StringUtils.isNotBlank(str) && !"1".equals(str)){
                                    isBasicAck =false;
                                    parkOrderInfo.setSerialNo(serialNo);
                                    // 抬杆播报
                                    ledCallInterface.FieldFeeAll(parkOrderInfo.getSerialNo(), plateNo);
                                    // 清除缓存
                                    cacheUtil.delete(CacheConstant.CURRENT_EXIT_LICENSE_PLATE,serialNo);
                                    // 车辆出场缓存车辆，处理重复出场
                                    cacheUtil.put(CacheConstant.PARK_CAR_OUT, serialNo, plateNo);
                                    log.info("场内码支付成功缓存当前车道已出场车牌信息->{},车道信息->{}",plateNo,serialNo);
                                }

                            }
                        }
                            if (isBasicAck){
                                //确认消息
                                parkCarOutEntranceRecordService.assemblyCarOutEntranceOrderInfoRecord(parkOrderInfo);
                                channel.basicAck(deliveryTag, false);
                                return;
                            }
                    }
                    ParkCarEnterLog carEnterLog = parkCarEnterLogMapper.selectById(parkOrderInfo.getCarEnterId());
                    if (null != carEnterLog) {
                        //组装出场记录
                        BeanUtils.copyProperties(carEnterLog, parkCarOutLog);
                        parkCarOutLog.setCarEnterId(carEnterLog.getId());
                        parkCarOutLog.setSerialNo(parkOrderInfo.getSerialNo());
                        parkCarOutLog.setCarOutTime(DateUtil.fomatDateTimeStr(new Date()));
                        parkCarOutLog.setCreateTime(new Date());
                        parkCarOutLog.setId(SnowFlakeUtil.getId());
                        parkCarOutLog.setOssImgPath(ossImg);
                        parkCarOutLog.setOuterType(1);
                        parkCarOutLog.setImgPath(img);
                        parkCarOutLog.setArmName(armName);
                        if ("_无_".equals(plateNo)) {
                            parkCarOutLog.setPlateNo("无牌车");
                        }
                        parkCarOutLogMapper.insert(parkCarOutLog);
                        //支付成功后将取消出场的异常记录删除
                        parkCarAbnormalRecordService.deletedLastestAbnormalRecord(carEnterLog.getParkCode(),carEnterLog.getPlateNo(),parkOrderInfo
                                .getSerialNo());
                        //parkSpaceService.updateParkStatus(carEnterLog, JddConstant.ParkSpace.PARKSTATUS_ZERO);
                        parkSpaceService.updateParkStatusV3(carEnterLog, JddConstant.ParkSpace.PARKSTATUS_ZERO, plateNo);
                        // 扫出口码支付成功后新版月租车处理逻辑
                        try {
                            sdkIdentifyResultPushLogV3Service.isMonthly(carEnterLog);
                        } catch (Exception e) {
                            log.info("车辆扫出口码出场转卡错误->{}", e);
                            e.printStackTrace();
                        }

                        ParkArmInfo parkArmInfo = parkArmInfoMapper.queryParkArmInfoBySerialNo(parkOrderInfo.getSerialNo());
                        //加上工作站名和岗亭人账户
                        String workUser = parkWorkStationService.getStationOperationNameByParkArm(parkArmInfo);
                        JSONObject successOrder = new JSONObject();
                        successOrder.put("successOrder", parkOrderInfo);
                        socketServer.sendInfo(successOrder.toJSONString(), parkArmInfo.getUsedUserId());


                        parkCarOutEntranceRecordService.assemblyCarOutEntranceRecord(parkCarOutLog);
                        //更新交接班
                        try {
                            //如果是个出口码，有车道的序列号或者id，则赋值当前车道值班人的
                            if (parkOrderInfo.getSerialNo() != null) {
                                parkOrderInfo.setSysUserName(workUser);
                                parkOrderInfoMapper.updateById(parkOrderInfo);
                            }
                            //钱数和出场数都更新
                            upHandLogAll(parkCarOutLog, abnormal, workUser);
                            //根据车牌号 车场编号修改入场记录
                            parkCarEnterLogMapper.updateIsOut(carEnterLog.getPlateNo());
                            //扫过出场码，临停车收费更新
                            Map<String, Object> data = parkArmInfoService.getData(workUser);
                            socketServer.sendMessageAll(JSONObject.toJSONString(data));
                            //放到缓存,处理收费后重复识别问题
                            cacheUtil.put(CURRENT_EXIT_LICENSE_PLATE_TEN, parkArmInfo.getSerialNo(), plateNo);
                        } catch (Exception e) {
                            log.error("-------------出口码支付后更新交接班记录失败-------------");
                        }
                        //同步云端出场记录
                        synchronousCloud(parkCarOutLog);
                    }
                } catch (Exception e) {
                    log.error("消息消费异常，丢弃消息", e);
                    channel.basicNack(deliveryTag, false, false);
                    return;
                }
            }
        }
        //抬杆消息
        //TODO 分秒待开发
        if (MessageTypeConstant.MESSAGE_TYPE_LIFTING_ROD.equals(rabbitMqMessage.getMessageType())) {
            ParkCarEnterLog msParkCarEnterLog = null;
            msParkCarEnterLog = JSON.parseObject(rabbitMqMessage.getMessageBody(), ParkCarEnterLog.class);
            sdkCallInterface.SdkUnfoldAll(msParkCarEnterLog.getSerialNo());
            String str = null;
            if (msParkCarEnterLog.getSerialNo() != null) {
                ParkArmInfo parkArmInfo = parkArmInfoMapper.queryParkArmInfoBySerialNo(msParkCarEnterLog.getSerialNo());
                if (parkArmInfo != null && parkArmInfo.getArmType() != null) {
                    if (JddConstant.StringNumber.STRING_ZERO.equals(parkArmInfo.getArmType())) {
                        str = "欢迎光临";
                    } else {
                        str = "祝您一路顺风";
                    }
                }
            }
            sdkCallInterface.Sdk485VoiceCommunicationAll(msParkCarEnterLog.getSerialNo(), str);
        }

        //APP抬杆消息
        if (MessageTypeConstant.APP_MESSAGE_TYPE_LIFTING_ROD.equals(rabbitMqMessage.getMessageType())) {
            ParkCarEnterLog msParkCarEnterLog = null;
            Result<String> result = new Result<String>();

            try {
                msParkCarEnterLog = JSON.parseObject(rabbitMqMessage.getMessageBody(), ParkCarEnterLog.class);
            } catch (Exception e) {
                log.error("消息转换异常:{}", e.getMessage());
                //非法消息，抛弃此条消息
                channel.basicNack(deliveryTag, false, false);
                return;
            }

            if (StringUtils.isBlank(rabbitMqMessage.getMessageType()) || StringUtils.isBlank(rabbitMqMessage.getMessageBody())) {
                log.info("空消息{}", JSON.toJSONString(rabbitMqMessage));
                //空消息，抛弃此条消息
                channel.basicNack(deliveryTag, false, false);
                return;
            }

            //处理消息
            try {
                if (StringUtils.isBlank(msParkCarEnterLog.getSerialNo())) {
                    result.error500("远程开闸失败:序列号为空");
                    throw new JddException(500, result.getMessage());
                }

                //根据序列号查询车道
                ParkArmInfo parkArmInfo = parkArmInfoMapper.queryParkArmInfoBySerialNo(msParkCarEnterLog.getSerialNo());

                //判断根据序列号查询车道是否存在
                if (null == parkArmInfo) {
                    result.error500("远程开闸:车道信息为空");
                    throw new JddException(500, result.getMessage());
                }

                //判断车道类型是否为空
                if (StringUtils.isBlank(parkArmInfo.getArmType())) {
                    result.error500("远程开闸失败:车道类型为空");
                    throw new JddException(500, result.getMessage());
                }

                //开闸操作
                Result unfoldResult = sdkCallInterface.SdkUnfoldAll(msParkCarEnterLog.getSerialNo());
                if (unfoldResult.getCode() != 200) {
                    result.error500("远程开闸失败:" + unfoldResult.getMessage());
                    throw new JddException(500, result.getMessage());
                }

                String str;
                if (JddConstant.StringNumber.STRING_ZERO.equals(parkArmInfo.getArmType())) {
                    str = "欢迎光临";
                } else {
                    str = "祝您一路顺风";
                }

                //语音播报
                Result voiceResult = sdkCallInterface.Sdk485VoiceCommunicationAll(msParkCarEnterLog.getSerialNo(), str);
                if (voiceResult.getCode() != 200) {
                    result.error500("远程开闸成功:播报失败");
                    throw new JddException(500, result.getMessage());
                }

                result.success("开闸成功！");

                //确认消息
                channel.basicAck(deliveryTag, false);
            } catch (Exception e) {
                result.error500(e.getMessage());
                log.error("处理消息异常：{}", e.getMessage());
                //抛弃此条消息
                channel.basicNack(deliveryTag, false, false);
            }

            //发送开闸结果到app
            OpenGateVo openGateVo = new OpenGateVo();
            openGateVo.setId(msParkCarEnterLog.getId());
            openGateVo.setCode(result.getCode());
            openGateVo.setMessage(result.getMessage());
            monthlyUploadHttpUtils.postMonthlyUpload("", openGateVo);
        }

        //无牌车入口码同步入场记录
        if (MessageTypeConstant.MESSAGE_TYPE_ENTRANCE.equals(rabbitMqMessage.getMessageType())) {
            log.info("无牌车入口码同步入场记录:{}", rabbitMqMessage.getMessageBody());
            ParkCarEnterLog parkCarEnterLog = null;
            try {
                parkCarEnterLog = JSON.parseObject(rabbitMqMessage.getMessageBody(), ParkCarEnterLog.class);
            } catch (Exception e) {
                log.error("消息(入场纪录)转换异常", e.getMessage());
                //非法消息，抛弃此条消息
                channel.basicNack(deliveryTag, false, false);
                return;
            }
            try {
                if (null != parkCarEnterLog) {
                    String ossImg = null;
                    String img = null;
                    String armName = null;
                    Map<String, String> map = getCarInfo(parkCarEnterLog.getSerialNo());
                    if (null != map && map.size() > 0) {
                        ossImg = map.get("ossImg");
                        img = map.get("img");
                        armName = map.get("armName");
                    }
                    parkCarEnterLog.setOssImgPath(ossImg);
                    parkCarEnterLog.setImgPath(img);
                    parkCarEnterLog.setArmName(armName == null ? parkCarEnterLog.getArmName() : armName);

                    parkCarEnterLog.setSynchronousStatus(JddConstant.SaveCloudType.SAVE_SUCCESS);
                    parkCarEnterLogMapper.insert(parkCarEnterLog);
                }
            } catch (Exception e) {
                log.info("同步无牌车入场记录异常:{}", e.getMessage());
            }
        }
        //无牌车支付费用0元 同步云端出场纪录
        if (MessageTypeConstant.MESSAGE_TYPE_APPEARANCE.equals(rabbitMqMessage.getMessageType())) {
            log.info("无牌车支付费用0元同步云端出场纪录:{}", rabbitMqMessage.getMessageBody());
            ParkCarOutLog parkCarOutLog = null;
            try {
                parkCarOutLog = JSON.parseObject(rabbitMqMessage.getMessageBody(), ParkCarOutLog.class);
            } catch (Exception e) {
                log.error("消息(出场纪录)转换异常", e.getMessage());
                //非法消息，抛弃此条消息
                channel.basicNack(deliveryTag, false, false);
                return;
            }
            try {
                if (null != parkCarOutLog) {
                    //新增出场记录
                    parkCarOutLogMapper.insert(parkCarOutLog);
                    //出场纪录是否同步状态设置为已完成
                    parkCarOutLog.setSynchronousStatus(JddConstant.SaveCloudType.SAVE_SUCCESS);
                    parkCarEnterLogMapper.IdUpdateIsOut(parkCarOutLog.getCarEnterId(), JddConstant.StringNumber.STRING_ONE);
                }
            } catch (Exception e) {
                log.info("同步无牌车0元出场记录失败:{}", e.getMessage());
            }
        }

        //接受云端消息，同步訪客記錄
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_DATA.equals(rabbitMqMessage.getMessageType())) {
            synVisitor(rabbitMqMessage, deliveryTag, channel);
        }

        //接受云端信息，同步新增月租车信息并编辑车位
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_MONTHLY_DATA.equals(rabbitMqMessage.getMessageType())) {
            synCloudCarMonthly(rabbitMqMessage, deliveryTag, channel);
        }

        //接受云端信息，同步新增月租车车位信息
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_ADD_SPACE_DATA.equals(rabbitMqMessage.getMessageType())) {
            synAddCloudSpace(rabbitMqMessage, deliveryTag, channel);
        }
        //接受云端信息，同步编辑月租车车位信息并编辑月租车
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_EDIT_SPACE_DATA.equals(rabbitMqMessage.getMessageType())) {
            synEditCloudSpace(rabbitMqMessage, deliveryTag, channel);
        }
        //接受云端信息，延期月租车车位/月租车、并新增延期记录
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_DELAY_SPACE_DATA.equals(rabbitMqMessage.getMessageType())) {
            synDelayCloudSpace(rabbitMqMessage, deliveryTag, channel);
        }
        //接受云端信息，删除月租车信息-编辑月租车车位
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_DELETE_MONTHLY_DATA.equals(rabbitMqMessage.getMessageType())) {
            synRemoveBindCarCloudSpace(rabbitMqMessage, deliveryTag, channel);
        }
        //接受云端信息，删除月租车位-删除月租车信息
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_DELETE_SPACE_DATA.equals(rabbitMqMessage.getMessageType())) {
            synDeleteCloudSpace(rabbitMqMessage, deliveryTag, channel);
        }
        //接受云端信息，批量删除月租车位-删除月租车信息
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_DELETE_SPACE_LIST_DATA.equals(rabbitMqMessage.getMessageType())) {
            synDeleteCloudSpaceList(rabbitMqMessage, deliveryTag, channel);
        }
        //接受云端信息，数据同步月租车入场车辆停靠状态
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_ENTRANCE_MONTHLY_DATA.equals(rabbitMqMessage.getMessageType())) {
            synEditCloudSpaceDockStatus(rabbitMqMessage, deliveryTag, channel);
        }
        //接受云端信息，数据同步入场记录保存-更改车辆车位的状态
        if (MessageTypeConstant.MESSAGE_TYPE_SYN_ENTRANCE_SAVE_DATA.equals(rabbitMqMessage.getMessageType())) {
            synEntranceSaveCloudSpace(rabbitMqMessage, deliveryTag, channel);
        }
        //接受云端信息，无牌车入场扫码openid
     /*   if (MessageTypeConstant.MESSAGE_TYPE_UNLICENSEDCAR_ENTER.equals(rabbitMqMessage.getMessageType())) {
            log.info("无牌车入场扫码:{}", rabbitMqMessage.getMessageBody());
            Map<String, String> map = new LinkedHashMap<>();
            try {
                map = JSON.parseObject(rabbitMqMessage.getMessageBody(), Map.class);
                String openid = map.get("openid");
                String parkCode = map.get("parkCode");
                String serialNo = map.get("serialNo");
                String thePlateNo = map.get("plateNo");
                String ossImg = map.get("ossImg");
                ParkArmInfo parkArmInfo = parkArmInfoMapper.queryParkArmInfoBySerialNo(serialNo);
                if(null == parkArmInfo){
                    log.error("无牌车入场-场端车道不存在");
                    throw new Exception("无牌车入场-场端车道不存在");
                }
                if (StringUtils.isBlank(parkArmInfo.getTargetAreaId())) {
                    log.error("无牌车入场-非入场车道");
                    throw new Exception("无牌车入场-非入场车道");
                }
                //组装识别信息
                SdkIdentifyResultPushLog sdkIdentifyResultPushLog = new SdkIdentifyResultPushLog();
                sdkIdentifyResultPushLog.setId(SnowFlakeUtil.getId());
                sdkIdentifyResultPushLog.setIpAddr(parkArmInfo.getIpAddr());
                sdkIdentifyResultPushLog.setParkCode(parkCode);
                sdkIdentifyResultPushLog.setParkName(parkArmInfo.getParkName());
                sdkIdentifyResultPushLog.setSerialNo(serialNo);
                sdkIdentifyResultPushLog.setCreateTime(new Date());
                sdkIdentifyResultPushLog.setLicense(thePlateNo);
                sdkIdentifyResultPushLog.setNTime(Integer.valueOf(DateUtil.newDate()));
                sdkIdentifyResultPushLog.setNType(1);
                sdkIdentifyResultPushLog.setNDirection(0);
                sdkIdentifyResultPushLog.setOpenid(openid);
                sdkIdentifyResultPushLog.setOssImg(ossImg);
                //保存数据
              //  sdkIdentifyResultPushLogService.save(sdkIdentifyResultPushLog);
                //判断出入场
                sdkIdentifyResultPushLogService.identifyJudge(sdkIdentifyResultPushLog,parkArmInfo);
                return;
            }catch (Exception e){
                log.error("消息消费异常，丢弃消息", e.getMessage());
                channel.basicNack(deliveryTag, false, false);
                return;
            }
        }*/

        //接受云端信息，无牌车--车辆未出场禁止再次入场
        if (MessageTypeConstant.MESSAGE_TYPE_CAR_NOT_OUT.equals(rabbitMqMessage.getMessageType())) {
            log.info("云端通知车辆未出场禁止再次入场:{}", rabbitMqMessage.getMessageBody());
            //不播报
 /*           try {
                String  serialNo = JSON.parseObject(rabbitMqMessage.getMessageBody(), String.class);
                //播报禁止入场
                log.info("车辆未出场，不允许再次进场");
                ledCallInterface.RefuseCarEnterAll(serialNo, "无牌车");
            }catch (Exception e){
                log.error("消息消费异常，丢弃消息", e.getMessage());
                channel.basicNack(deliveryTag, false, false);
                return;
            }*/
        }
        //接受云端信息，无牌车--临时车位已满
        if (MessageTypeConstant.MESSAGE_TYPE_TEMPORARY_PARK_NONE.equals(rabbitMqMessage.getMessageType())) {
            log.info("云端通知车辆未出场禁止再次入场:{}", rabbitMqMessage.getMessageBody());
            try {
                String serialNo = JSON.parseObject(rabbitMqMessage.getMessageBody(), String.class);
                log.info("临时车位已满，禁止驶入");
                ledCallInterface.TemporaryEntranceParkingFullAll(serialNo, "无牌车");
                return;
            } catch (Exception e) {
                log.error("消息消费异常，丢弃消息", e.getMessage());
                channel.basicNack(deliveryTag, false, false);
                return;
            }
        }
        //接受云端信息，临时车入场自动开闸
        if (MessageTypeConstant.MESSAGE_TYPE_TEMPORARY_ENYER_AUTO.equals(rabbitMqMessage.getMessageType())) {
            log.info("云端通知临时车入场自动开闸:{}", rabbitMqMessage.getMessageBody());
            try {
                String serialNo = JSON.parseObject(rabbitMqMessage.getMessageBody(), String.class);
                log.info("临时车入场，自动开闸serialNo:{}", serialNo);
                ledCallInterface.TemporaryEntranceInConfigAll(serialNo, "无牌车");
                return;
            } catch (Exception e) {
                log.error("消息消费异常，丢弃消息", e.getMessage());
                channel.basicNack(deliveryTag, false, false);
                return;
            }
        }
        //接受云端信息，临时车入场确认开闸
        if (MessageTypeConstant.MESSAGE_TYPE_TEMPORARY_ENYER_CONFIEM.equals(rabbitMqMessage.getMessageType())) {
            log.info("云端通知临时车入场确认开闸:{}", rabbitMqMessage.getMessageBody());
            try {
                String serialNo = JSON.parseObject(rabbitMqMessage.getMessageBody(), String.class);
                log.info("临时车入场，确认开闸");
                ledCallInterface.TemporaryInConfigAll(serialNo, "无牌车");
                //发送webSockt消息到前端
                ParkArmInfo parkArmInfo = parkArmInfoMapper.queryParkArmInfoBySerialNo(serialNo);
                if (null == parkArmInfo) {
                    log.error("车道不存在");
                    return;
                }
                sendInfo(serialNo, "无牌车", parkArmInfo, JddConstant.VehicleType.TEMPORARYCAR, "0", "");
                return;
            } catch (Exception e) {
                log.error("消息消费异常，丢弃消息", e.getMessage());
                channel.basicNack(deliveryTag, false, false);
                return;
            }
        }

        //接受云端信息，临时车入场确认开闸存储 openid
        if (MessageTypeConstant.MESSAGE_TYPE_TEMPORARY_ENYER_CONFIEM_OPENID.equals(rabbitMqMessage.getMessageType())) {
            log.info("云端通知临时车入场确认开闸openId信息:{}", rabbitMqMessage.getMessageBody());
            try {
                HashMap openIdInfo = JSON.parseObject(rabbitMqMessage.getMessageBody(), HashMap.class);
                log.info("临时车入场，确认开闸openIdInfo：{}", JSON.toJSONString(openIdInfo));
                cacheUtil.put(CacheConstant.PARK_CAR_ENTER_OPEN_ID, String.valueOf(openIdInfo.get("serialNo")), openIdInfo.get("openId"));
                return;
            } catch (Exception e) {
                log.error("消息消费异常，丢弃消息", e.getMessage());
                channel.basicNack(deliveryTag, false, false);
                return;
            }
        }

        //接受云端信息，临时车入场禁止
        if (MessageTypeConstant.MESSAGE_TYPE_TEMPORARY_ENYER_ABANDON.equals(rabbitMqMessage.getMessageType())) {
            log.info("云端通知临时车入场禁止:{}", rabbitMqMessage.getMessageBody());
            try {
                String serialNo = JSON.parseObject(rabbitMqMessage.getMessageBody(), String.class);
                log.info("临时车入场，不开闸");
                ledCallInterface.TemporaryBanEntranceAll(serialNo, "无牌车");
                return;
            } catch (Exception e) {
                log.error("消息消费异常，丢弃消息", e.getMessage());
                channel.basicNack(deliveryTag, false, false);
                return;
            }
        }

    }

    /*** 功能描述: 扫出口码后更新交接班记录
     * @Author: lcy
     * @Date: 2021/12/2
     */
    private void upHandLogAll(ParkCarOutLog parkCarOutLog, int abnormal, String workUser) {
        // TODO: 2021/12/2  A上班，场内码无法判定哪个车道哪个工作站
        // TODO: 2021/12/2  暂时先把出口码算到当前上班的车道的工作站
        //查询该车辆的所有订单
        List<ParkOrderInfo> orderInfos = parkOrderInfoMapper.getOrderByCarEnterId(parkCarOutLog.getCarEnterId());
        //计算总的钱数
        if (ObjectUtil.isEmpty(orderInfos)) {
            return;
        }
        ParkOrderInfo parkOrderInfo = new ParkOrderInfo();
        parkOrderInfo.setOrderStatus(JddConstant.OrderConstant.ORDER_PAY_STATE_SUCCESS);
        //设置成线上收费
        parkOrderInfo.setPayType("1");
        BigDecimal chargeDue = new BigDecimal(0);
        BigDecimal chargePaid = new BigDecimal(0);
        BigDecimal couponAmt = new BigDecimal(0);
        for (ParkOrderInfo orderInfo : orderInfos) {
            chargePaid = chargePaid.add(new BigDecimal(null == orderInfo.getChargePaid() ? "0" : orderInfo.getChargePaid()));
            couponAmt = couponAmt.add(new BigDecimal(null == orderInfo.getCouponAmt() ? "0" : orderInfo.getCouponAmt()));
            // paid+couponamt是应收
            chargeDue = chargePaid.add(couponAmt);
        }
        parkOrderInfo.setChargePaid(chargePaid.toString());
        parkOrderInfo.setChargeDue(chargeDue.toString());
        parkOrderInfo.setCouponAmt(couponAmt.toString());

        if (!JddConstant.StringNumber.STRING_ZERO.equals(couponAmt.toString()) && couponAmt.toString().equals(chargeDue.toString())) {
            parkCarOutLog.setFreeAllCoupon(true);
        }
        //更新钱数也更新出场数
        parkHandOverLogService.updateHandOverAuto(parkCarOutLog, parkOrderInfo, workUser, abnormal);
    }

    /**
     * 接受云端信息，批量删除月租车位-删除月租车信息
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/14 17:43:51
     * @version 1.0
     */
    private void synDeleteCloudSpaceList(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        List<String> idList = new ArrayList<>();
        try {
            idList = JSON.parseObject(rabbitMqMessage.getMessageBody(), ArrayList.class);
        } catch (Exception e) {
            log.error("消息(批量删除月租车位)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        try {
            List<String> parkNumberList = parkSpaceService.listByIds(idList).stream().map(ParkSpace::getParkNumber).collect(Collectors.toList());
            List<CompletableFuture<Boolean>> futureList = new ArrayList<>();
            int pageSize = 50;
            int pageNumber = parkNumberList.size() / pageSize;
            for (int index = 0; index <= pageNumber; index++) {
                List<String> parkNumberListPage;
                if (index == pageNumber) {
                    parkNumberListPage = parkNumberList.subList(index * pageSize, parkNumberList.size());
                } else {
                    parkNumberListPage = parkNumberList.subList(index * pageSize, (index + 1) * pageSize);
                }
                CompletableFuture<Boolean> completableFuture = CompletableFuture.supplyAsync(() -> {
                    return removeParkCarMonthlyByParkSpace(parkNumberListPage, parkCode);
                }, executorService);
                futureList.add(completableFuture);
            }
            CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();
            boolean parkSpaceRemove = parkSpaceService.removeByIds(idList);
            log.info("批量删除月租车位:{}", parkSpaceRemove);
        } catch (Exception e) {
            log.error("批量删除月租车位一场:{}", e.getMessage());
            e.printStackTrace();
        }
    }

    private boolean removeParkCarMonthlyByParkSpace(List<String> parkNumberList, String parkCode) {
        LambdaQueryWrapper<ParkCarMonthly> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParkCarMonthly::getParkCode, parkCode);
        if (CollectionUtil.isNotEmpty(parkNumberList)) {
            queryWrapper.in(ParkCarMonthly::getParkNumber, parkNumberList);
            return parkCarMonthlyService.remove(queryWrapper);
        } else {
            return false;
        }
    }

    /**
     * 接受云端信息，数据同步入场记录保存-更改车辆车位的状态
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/14 15:54:25
     * @version 1.0
     */
    private void synEntranceSaveCloudSpace(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        ParkCarEnterLog lastCarEnterLog = new ParkCarEnterLog();
        try {
            lastCarEnterLog = JSON.parseObject(rabbitMqMessage.getMessageBody(), ParkCarEnterLog.class);
        } catch (Exception e) {
            log.error("消息(修改月租车位车辆停靠状态)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        log.info("更新月租车位状态,区域id:{},车位号：{}", lastCarEnterLog.getAreaId(), lastCarEnterLog.getParkNumber());
        UpdateWrapper<ParkSpace> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("area_id", lastCarEnterLog.getAreaId())
                .eq("park_number", lastCarEnterLog.getParkNumber())
                .set("park_status", JddConstant.ParkSpace.PARKSTATUS_ZERO);
        Boolean ok = parkSpaceService.update(updateWrapper);
        log.info("更新月租车位状态:{}", ok);
    }

    /**
     * 接受云端信息，数据同步月租车入场车辆停靠状态
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/14 15:18:47
     * @version 1.0
     */
    private void synEditCloudSpaceDockStatus(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        HashMap<String, String> hashMap;
        try {
            hashMap = JSON.parseObject(rabbitMqMessage.getMessageBody(), HashMap.class);
        } catch (Exception e) {
            log.error("消息(修改月租车位车辆停靠状态)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        try {
            //车位信息
            String parkCarEnterLogStr = hashMap.get("parkCarEnterLog");
            ParkCarEnterLog parkCarEnterLog = JSONObject.parseObject(parkCarEnterLogStr, ParkCarEnterLog.class);

            //月租车信息
            String latestParkCarEnterLogStr = hashMap.get("latestParkCarEnterLog");
            ParkCarEnterLog latestParkCarEnterLog = JSONObject.parseObject(latestParkCarEnterLogStr, ParkCarEnterLog.class);

            log.info("更新月租车位状态,区域id:{},车位号：{}", parkCarEnterLog.getAreaId(), parkCarEnterLog.getParkNumber());
            UpdateWrapper<ParkSpace> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("area_id", parkCarEnterLog.getAreaId())
                    .eq("park_number", parkCarEnterLog.getParkNumber())
                    .set("park_status", JddConstant.ParkSpace.PARKSTATUS_ONE);
            parkSpaceService.update(updateWrapper);

            log.info("更新月租车位状态,区域id:{},车位号：{}", parkCarEnterLog.getAreaId(), parkCarEnterLog.getParkNumber());
            UpdateWrapper<ParkSpace> updateLatestWrapper = new UpdateWrapper<>();
            updateLatestWrapper.eq("area_id", parkCarEnterLog.getAreaId())
                    .eq("park_number", parkCarEnterLog.getParkNumber())
                    .set("park_status", JddConstant.ParkSpace.PARKSTATUS_ZERO);
            parkSpaceService.update(updateLatestWrapper);

            log.info("数据同步月租车入场车辆停靠状态成功");

        } catch (Exception e) {
            e.printStackTrace();
            log.error("数据同步月租车入场车辆停靠状态失败:{}", e.getMessage());
        }
    }

    /**
     * 接受云端信息，删除月租车细心-删除月租车车位
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/14 14:39:19
     * @version 1.0
     */
    private void synDeleteCloudSpace(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        String id = null;
        try {
            id = JSON.parseObject(rabbitMqMessage.getMessageBody(), String.class);
        } catch (Exception e) {
            log.error("消息(删除月租车位)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        try {
            ParkSpace parkSpace = parkSpaceService.getById(id);
            LambdaQueryWrapper<ParkCarMonthly> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ParkCarMonthly::getParkCode, parkCode);
            queryWrapper.eq(ParkCarMonthly::getParkNumber, parkSpace.getParkNumber());
            parkCarMonthlyService.remove(queryWrapper);
            parkSpaceService.removeById(id);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 接受云端信息，删除月租车细心/编辑月租车车位
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/14 14:30:37
     * @version 1.0
     */
    private void synRemoveBindCarCloudSpace(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        String id = null;
        try {
            id = JSON.parseObject(rabbitMqMessage.getMessageBody(), String.class);
        } catch (Exception e) {
            log.error("消息(删除月租车)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        //删除月租车
        parkCarMonthlyService.removeById(id);

        // 查询该月租车信息所绑定的车位下，是否还绑定有其他车辆
        ParkCarMonthly parkCarMonthly = parkCarMonthlyService.getById(id);
        LambdaQueryWrapper<ParkCarMonthly> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParkCarMonthly::getParkCode, parkCode);
        queryWrapper.eq(ParkCarMonthly::getParkNumber, parkCarMonthly.getParkNumber());
        List<ParkCarMonthly> parkCarMonthlyList = parkCarMonthlyService.list(queryWrapper);
        if (parkCarMonthlyList.size() == 0) {
            LambdaQueryWrapper<ParkSpace> parkSpaceQueryWrapper = new LambdaQueryWrapper<>();
            parkSpaceQueryWrapper.eq(ParkSpace::getParkCode, parkCarMonthly.getParkCode());
            parkSpaceQueryWrapper.eq(ParkSpace::getParkNumber, parkCarMonthly.getParkNumber());
            ParkSpace parkSpace = resetParkSpace(parkSpaceService.getOne(parkSpaceQueryWrapper));
            //删除原车位信息
            parkSpaceService.removeById(parkSpace.getId());
            //新增清空基础信息后的车位
            parkSpaceService.save(parkSpace);
        }
    }

    /**
     * 清空车位基础信息
     *
     * @param parkSpace
     * @author jdd孙庆伟
     * @date 2021/10/14 14:35:05
     */
    private ParkSpace resetParkSpace(ParkSpace parkSpace) {
        parkSpace.setParkStatus("0");
        parkSpace.setStartTime(null);
        parkSpace.setEndTime(null);
        parkSpace.setPayFee(null);
        parkSpace.setUserName(null);
        parkSpace.setAddress(null);
        parkSpace.setMobile(null);
        parkSpace.setParkSpaceRemark(null);
        return parkSpace;
    }

    /**
     * 接受云端信息，延期月租车车位/月租车、并新增延期记录
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/14 09:35:02
     * @version 1.0
     */
    private void synDelayCloudSpace(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        HashMap<String, String> hashMap;
        try {
            hashMap = JSON.parseObject(rabbitMqMessage.getMessageBody(), HashMap.class);
        } catch (Exception e) {
            log.error("消息(延期月租车车位)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        try {
            //车位信息
            String parkSpaceStr = hashMap.get("parkSpace");
            ParkSpace parkSpace = JSONObject.parseObject(parkSpaceStr, ParkSpace.class);

            //月租车信息
            JSONArray objects = JSONArray.parseArray(hashMap.get("parkCarMonthly"));
            List<ParkCarMonthly> parkCarMonthlyList = objects.toJavaList(ParkCarMonthly.class);

            //延期记录
            String parkWhiteEditStr = hashMap.get("parkWhiteEdit");
            ParkWhiteEditList parkWhiteEditList = JSONObject.parseObject(parkWhiteEditStr, ParkWhiteEditList.class);

            Boolean updateSpace = parkSpaceService.updateById(parkSpace);
            if (updateSpace) {
                Boolean updateMonthly = parkCarMonthlyService.updateBatchById(parkCarMonthlyList);
                if (updateMonthly) {
                    Boolean ok = parkWhiteEditListService.save(parkWhiteEditList);
                    log.info("同步云端延期月租车位:{}", ok);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("同步延期月租车位落库异常:{}", e.getMessage());
        }
    }

    /**
     * 接受云端信息，同步编辑车位信息
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/13 17:10:21
     * @version 1.0
     */
    private void synEditCloudSpace(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        HashMap<String, String> carMonthlyMap;
        try {
            carMonthlyMap = JSON.parseObject(rabbitMqMessage.getMessageBody(), HashMap.class);
        } catch (Exception e) {
            log.error("消息(编辑月租车车位)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        try {
            //车位信息
            String parkSpaceStr = carMonthlyMap.get("parkSpace");
            ParkSpace parkSpace = JSONObject.parseObject(parkSpaceStr, ParkSpace.class);

            //月租车信息
            JSONArray objects = JSONArray.parseArray(carMonthlyMap.get("parkCarMonthly"));
            List<ParkCarMonthly> parkCarMonthlyList = objects.toJavaList(ParkCarMonthly.class);

            Boolean updateSpace = parkSpaceService.updateById(parkSpace);
            if (updateSpace) {
                Boolean updateMonthly = parkCarMonthlyService.updateBatchById(parkCarMonthlyList);
                log.info("同步编辑月租车车位:{}", updateMonthly);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("同步编辑月租车位落库异常:{}", e.getMessage());
        }
    }

    /**
     * 接受云端信息，同步新增车位信息
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/13 17:01:06
     * @version 1.0
     */
    private void synAddCloudSpace(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        ParkSpace parkSpace = new ParkSpace();
        try {
            parkSpace = JSON.parseObject(rabbitMqMessage.getMessageBody(), ParkSpace.class);
        } catch (Exception e) {
            log.error("消息(新增月租车车位)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        Boolean ok = parkSpaceService.save(parkSpace);
        log.info("同步新增云端月租车信息:{}", ok);
    }

    /**
     * 接受云端信息，同步新增月租车信息并编辑车位信息
     *
     * @param rabbitMqMessage
     * @param deliveryTag
     * @param channel
     * @return void
     * @author jdd孙庆伟
     * @date 2021/10/13 10:47:36
     * @version 1.0
     */
    public void synCloudCarMonthly(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        HashMap<String, String> hashMap;
        try {
            hashMap = JSON.parseObject(rabbitMqMessage.getMessageBody(), HashMap.class);
        } catch (Exception e) {
            log.error("消息(同步新增月租车)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }
        //车位信息
        String parkSpaceStr = hashMap.get("parkSpace");
        ParkSpace parkSpace = JSONObject.parseObject(parkSpaceStr, ParkSpace.class);

        //月租车信息
        String parkCarMonthlyStr = hashMap.get("parkCarMonthly");
        ParkCarMonthly parkCarMonthly = JSONObject.parseObject(parkCarMonthlyStr, ParkCarMonthly.class);

        //编辑车位信息
        Boolean updateSpace = parkSpaceService.updateById(parkSpace);
        if (updateSpace) {
            //新增月租车信息
            Boolean ok = parkCarMonthlyService.save(parkCarMonthly);
            log.info("同步新增月租车:{}", ok);
        }
    }


    public void synVisitor(RabbitMqMessage rabbitMqMessage, Long deliveryTag, Channel channel) throws IOException {
        VisitorRecord visitorRecord = null;
        try {
            visitorRecord = JSON.parseObject(rabbitMqMessage.getMessageBody(), VisitorRecord.class);
        } catch (Exception e) {
            log.error("消息(同步访客记录)转换异常", e.getMessage());
            //非法消息，抛弃此条消息
            channel.basicNack(deliveryTag, false, false);
            return;
        }

        //同步场端访客记录如果存在则更新 否则插入
        VisitorRecord visitorRecord1 = this.visitorRecordMapper.selectById(visitorRecord.getId());
        if (ObjectUtils.isNotEmpty(visitorRecord1)) {
            //更新
            this.visitorRecordMapper.updateById(visitorRecord);
        } else {
            //插入
            this.visitorRecordMapper.insert(visitorRecord);
        }

        //白名单添加
        ParkWhiteList parkWhiteList = new ParkWhiteList();
        visitorRecord.setLicenseType(null);
        visitorRecord.setId(null);
        BeanUtils.copyProperties(visitorRecord, parkWhiteList);
        parkWhiteList.setLicenseType(1);
        QueryWrapper<ParkWhiteList> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", parkWhiteList.getUserName());
        queryWrapper.eq("plate_no", parkWhiteList.getPlateNo());
        queryWrapper.eq("park_code", parkWhiteList.getParkCode());
        ParkWhiteList parkWhiteList1 = this.parkWhiteListMapper.selectOne(queryWrapper);
        if (ObjectUtils.isNotEmpty(parkWhiteList1)) {
            this.parkWhiteListMapper.updateById(parkWhiteList);
        } else {
            this.parkWhiteListMapper.insert(parkWhiteList);
        }
    }

    public Map<String, String> getCarInfo(String serialNo) {
        log.info("-----------------------" + serialNo);
        Map<String, String> map = new HashMap<>(16);
        String carInfo = cacheUtil.get(CacheConstant.CURRENT_EXIT_LICENSE_PLATE, serialNo);
        log.info("cache缓存内容>carInfo:{}", carInfo);
        if (StringUtils.isNotBlank(carInfo) && !"null".equalsIgnoreCase(carInfo)) {
            log.info("carInfo：" + carInfo);
            String[] carInfoArray = carInfo.split("#");
            if (ArrayUtils.isNotEmpty(carInfoArray) && carInfoArray.length >= 2) {
                map.put("plateNo", carInfoArray[0]);
                map.put("ossImg", carInfoArray[1]);
                map.put("img", carInfoArray[2]);
                map.put("armName", carInfoArray[3]);
            }
        }
        return map;
    }


    public Map<String, String> getCarInfos(String plateNoe) {
        System.out.println("-----------------------" + plateNoe);
        Map<String, String> map = new HashMap<>();
    	// 查询所有出口车道信息
    	LambdaQueryWrapper<ParkArmInfo> queryWrapper = Wrappers.lambdaQuery();
    	queryWrapper.eq(ParkArmInfo::getArmStatus, JddConstant.StringNumber.STRING_ONE);
    	queryWrapper.eq(ParkArmInfo::getArmType, JddConstant.StringNumber.STRING_ONE);
    	List<ParkArmInfo> armInfoList = parkArmInfoService.list(queryWrapper);
    	if(CollectionUtil.isNotEmpty(armInfoList)){
    		for(ParkArmInfo armInfo : armInfoList){
    			String value = cacheUtil.get(CacheConstant.CURRENT_EXIT_LICENSE_PLATE,armInfo.getSerialNo());
    			log.info("车道信息为->{},获取的缓存信息为->{}",JSON.toJSONString(armInfo),value);
    			if(StringUtils.isNotBlank(value)){
    				String[] carInfoArray = value.split("#");
                    if (plateNoe.equals(carInfoArray[0])){
                        map.put("plateNo", carInfoArray[0]);
                        map.put("ossImg", carInfoArray[1]);
                        map.put("img", carInfoArray[2]);
                        map.put("armName", carInfoArray[3]);
                        map.put("serialNo", armInfo.getSerialNo());
                        break;
                    }
    			}
    		}
    	}
        return map;
    }

    /**
     * 同步到云端出场记录
     *
     * @param parkCarOutLog
     * @return void
     * @author jdd孙庆伟
     * @date 2021/6/11 16:04:39
     * @version 1.0
     */
    public void synchronousCloud(ParkCarOutLog parkCarOutLog) {
        //调用云端保存出场记录接口 如果失败重试三次 并返回云端保存结果
        String url = "";
        //上传云端 图片路径修改成oss图片路径
        parkCarOutLog.setImgPath(parkCarOutLog.getOssImgPath());
        //云端保存结果 200：成功 400：失败
        String remoteResults = getRemoteResults(url, parkCarOutLog);
        //如果云端保存出场记录成功则修改场端出场记录 是否同步成功状态
        if (remoteResults.equals(JddConstant.SaveCloudType.SAVE_SUCCESS)) {
            parkCarOutLogMapper.editSynchronousStatus(parkCarOutLog.getId(), remoteResults);
        }
    }

    /**
     * 获得云端出/入场记录是否保存成功
     *
     * @param url    远程访问接口
     * @param object 远程传递参数
     * @return java.lang.String
     * @author jdd孙庆伟
     * @date 2021/5/28 15:25:57
     * @version 1.0
     */
    public String getRemoteResults(String url, Object object) {
        //调用云端入场记录保存
        int restTemplateCode = (int) GuavaRetryingUtils.retrySend(object, url, restTemplateUtils, appId, appScrect);
        //restTemplateCode为200则云端保存成功 restTemplateCode为400则云端保存失败
        return ResultVo.SUCCESS_CODE == restTemplateCode ? JddConstant.SaveCloudType.SAVE_SUCCESS : JddConstant.SaveCloudType.SAVE_ERROR;
    }

    /**
     * 车场入场确认开闸 发送webSockt消息 车场监控确认开闸
     *
     * @param serialNo
     * @param plateNo
     * @param parkArmInfo
     * @param vehicleType
     * @return void
     * @author jdd孙庆伟
     * @date 2021/8/28 15:40:15
     * @version 1.0
     */
    private void sendInfo(String serialNo, String plateNo, ParkArmInfo parkArmInfo, String vehicleType, String parkingIsFull, String imgPath) {
        try {
            WebSocketVo webSocketVo = new WebSocketVo();
            webSocketVo.setPlateNo(plateNo);
            webSocketVo.setVehicleType(vehicleType);
            webSocketVo.setArmName(parkArmInfo.getArmName());
            webSocketVo.setArmType(parkArmInfo.getArmType());
            webSocketVo.setSerialNo(serialNo);
            webSocketVo.setArmId(parkArmInfo.getId());
            webSocketVo.setParkingIsFull(parkingIsFull);
            webSocketVo.setImgPath(imgPath);
            webSocketVo.setCarEnterTime(DateUtil.fomatDateTimeStr(new Date()));
            socketServer.sendInfo(JSONObject.toJSONString(webSocketVo), parkArmInfo.getUsedUserId());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
